import asyncio
import httpx
from typing import Dict, Any, List
import structlog
from datetime import datetime, timedelta

from config.settings import settings

logger = structlog.get_logger()


class ServiceHealth:
    def __init__(self, name: str, config: Dict[str, Any]):
        self.name = name
        self.url = config["url"]
        self.health_check = config["health_check"]
        self.timeout = config["timeout"]
        self.retries = config["retries"]
        self.is_healthy = True
        self.last_check = None
        self.consecutive_failures = 0
        self.response_time = 0

    async def check_health(self) -> bool:
        """检查服务健康状态"""
        try:
            # 创建带超时和重试设置的客户端
            async with httpx.AsyncClient(
                timeout=httpx.Timeout(self.timeout),
                follow_redirects=True
            ) as client:
                start_time = datetime.now()
                response = await client.get(f"{self.url}{self.health_check}")
                self.response_time = (datetime.now() - start_time).total_seconds() * 1000

                if response.status_code == 200:
                    self.is_healthy = True
                    self.consecutive_failures = 0
                    logger.info(
                        "Service health check passed",
                        service=self.name,
                        response_time=f"{self.response_time:.2f}ms"
                    )
                else:
                    self.is_healthy = False
                    self.consecutive_failures += 1
                    logger.warning(
                        "Service health check failed",
                        service=self.name,
                        status_code=response.status_code
                    )

        except httpx.TimeoutException as e:
            self.is_healthy = False
            self.consecutive_failures += 1
            logger.error(
                "Service health check timeout",
                service=self.name,
                error=str(e),
                timeout=self.timeout
            )
        except httpx.ConnectError as e:
            self.is_healthy = False
            self.consecutive_failures += 1
            logger.error(
                "Service connection error",
                service=self.name,
                error=str(e)
            )
        except Exception as e:
            self.is_healthy = False
            self.consecutive_failures += 1
            logger.error(
                "Service health check error",
                service=self.name,
                error=str(e)
            )

        self.last_check = datetime.now()
        return self.is_healthy


class ServiceDiscovery:
    def __init__(self, services_config: Dict[str, Dict[str, Any]]):
        self.services: Dict[str, ServiceHealth] = {}
        self.health_check_task = None

        # 初始化服务
        for name, config in services_config.items():
            self.services[name] = ServiceHealth(name, config)

    async def start_health_check(self):
        """启动健康检查任务"""
        self.health_check_task = asyncio.create_task(self._health_check_loop())
        logger.info("Service health check started")

    async def stop_health_check(self):
        """停止健康检查任务"""
        if self.health_check_task:
            self.health_check_task.cancel()
            try:
                await self.health_check_task
            except asyncio.CancelledError:
                pass
            logger.info("Service health check stopped")

    async def _health_check_loop(self):
        """健康检查循环"""
        while True:
            try:
                # 检查所有服务的健康状态
                tasks = [service.check_health() for service in self.services.values()]
                await asyncio.gather(*tasks, return_exceptions=True)

                # 每60秒检查一次
                await asyncio.sleep(1800)

            except asyncio.CancelledError:
                logger.info("Health check loop cancelled")
                break
            except Exception as e:
                logger.error("Health check loop error", error=str(e))
                await asyncio.sleep(30)

    def get_healthy_services(self) -> Dict[str, ServiceHealth]:
        """获取所有健康的服务"""
        return {
            name: service for name, service in self.services.items()
            if service.is_healthy
        }

    def get_service(self, name: str) -> ServiceHealth:
        """获取指定服务"""
        return self.services.get(name)

    def get_service_status(self) -> Dict[str, Any]:
        """获取所有服务的状态"""
        return {
            name: {
                "url": service.url,
                "is_healthy": service.is_healthy,
                "last_check": service.last_check.isoformat() if service.last_check else None,
                "response_time": f"{service.response_time:.2f}ms",
                "consecutive_failures": service.consecutive_failures
            }
            for name, service in self.services.items()
        }